﻿using System;
using System.Drawing;
using System.Diagnostics;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Xml;
using System.Linq;

using Microsoft.WindowsMobile.Status;

namespace iPhoneUI.Widgets
{
    public enum SnapStyle
    {
        Top,
        Bottom,
        Fill,
        None
    }

    public abstract class Widget : IDisposable
    {
        private IWidgetOwner m_owner;
        private Rectangle m_clientArea;
        private Timer m_timer;
        private List<SystemState> m_stateChangeNotifications;
        private bool m_suspended;

        protected Widget()
        {
            Decorations = new List<Widget>();

            SnapStyle = SnapStyle.None;
        }

        public SnapStyle SnapStyle { get; set; }

        public IWidgetOwner Owner
        {
            get
            {
                return m_owner;
            }
        }

        public Point Location
        {
            set
            {
                if (m_clientArea.Location != value)
                {
                    m_clientArea.Location = value;
                    Layout();
                }
            }
            get
            {
                return m_clientArea.Location;
            }
        }

        public Size Size
        {
            set
            {
                if (m_clientArea.Size != value)
                {
                    m_clientArea.Size = value;
                    Layout();
                }
            }
            get
            {
                return m_clientArea.Size;
            }
        }

        public Rectangle ClientArea
        {
            get
            {
                return m_clientArea;
            }
            set
            {
                if (m_clientArea != value)
                {
                    m_clientArea = value;
                    Layout();
                }
            }
        }

        public IList<Widget> Decorations { get; set; }

        public void SetOwner(IWidgetOwner owner)
        {
            Debug.Assert(owner != null);

            m_owner = owner;
            OnSetOwner();
        }

        protected void SetInitialSize(Size size)
        {
            m_clientArea.Size = Owner.ScaleSize(size);
        }

        protected virtual void OnSetOwner()
        {
            foreach (Widget w in Decorations)
                w.SetOwner(Owner);
        }

        protected void RegisterSystemStateChange(SystemProperty property)
        {
            if (m_stateChangeNotifications == null)
                m_stateChangeNotifications = new List<SystemState>();

            SystemState state = new SystemState(property, true);
            state.Changed += new ChangeEventHandler(state_Changed);
            m_stateChangeNotifications.Add(state);
        }

        private void state_Changed(object sender, ChangeEventArgs args)
        {
            OnSystemStateChanged((SystemState)sender, args.NewValue);
        }

        protected virtual void OnSystemStateChanged(SystemState property, object newValue)
        {
            Update();            
        }

        public virtual void OwnerMouseMove(int x, int y)
        {
        }

        public virtual void OwnerMouseDown(int x, int y)
        {
        }

        public virtual void OwnerMouseUp(int x, int y)
        {
        }

        public virtual void Suspend()
        {
            m_suspended = true;
            if (m_timer != null)
                m_timer.Enabled = false;
        }

        public virtual void Resume()
        {
            m_suspended = false;
            if (m_timer != null)
                m_timer.Enabled = true;
        }

        public virtual void LayoutAsDecoration(Rectangle reference)
        {
        }

        public void SetUpdateTimer(int period)
        {
            if(m_timer != null)
                m_timer.Tick -= new EventHandler(m_timer_Tick);

            m_timer.SafeDispose();
            m_timer = new Timer();
            m_timer.Interval = period;
            m_timer.Tick += new EventHandler(m_timer_Tick);

            Resume();
        }

        private void m_timer_Tick(object sender, EventArgs e)
        {
            Update();
        }

        protected void Update()
        {
            if (m_suspended == false)
                Owner.Update(ClientArea);
        }

        protected virtual void Layout()
        {
            foreach (Widget w in Decorations)
                w.LayoutAsDecoration(ClientArea);
        }

        public bool HitTest(int x, int y)
        {
            return m_clientArea.Contains(x, y);
        }

        public bool HitTest(Point point)
        {
            return m_clientArea.Contains(point);
        }

        protected int CenterOn(int length, int target)
        {
            return target - length / 2;
        }

        public void Dispose()
        {
            OnDispose();
            m_owner = null;
        }

        public void Draw(Canvas canvas, Rectangle clipBounds)
        {
            try
            {
                // draw the widget, but only if it is within the clip area
                if (ClientArea.IntersectsWith(clipBounds))
                    OnDraw(canvas, Rectangle.Intersect(ClientArea, clipBounds));

                // and then any decoartions (which always go over the widget graphics)
                foreach (Widget w in Decorations.Where(w => w.ClientArea.IntersectsWith(clipBounds)))
                    w.Draw(canvas, Rectangle.Intersect(w.ClientArea, clipBounds));
            }
            catch (Exception e)
            {
                Debug.Write(e.Message);
                using (Pen pen = new Pen(Color.Red))
                    canvas.DrawRectangle(pen, ClientArea);
            }
        }

        protected abstract void OnDraw(Canvas canvas, Rectangle clipBounds);

        protected virtual void OnDispose()
        {
            if (m_timer != null)
                m_timer.Tick -= new EventHandler(m_timer_Tick);

            if (m_stateChangeNotifications != null)
                m_stateChangeNotifications.DisposeAll();
  
            m_timer.SafeDispose();

            Decorations.DisposeAll();
            Decorations.Clear();
        }
    }
}
